package initoy

import (
	"os"
	"fmt"
	"strings"
)

type Configuration struct {
	sourceFile	string
	sections	map[string]*Section
	sectionList []string
}

// 构造新的已绑定至`@filename`文件的空Configuration结构体
func NewConfiguration(filename string) *Configuration {
	return &Configuration{
		sourceFile : filename,
		sections   : make(map[string]*Section),
	}
}

// 在Configuration中添加以`@section`为名称的空Section结构体，并返回其指针
func (c *Configuration)NewSection(section string) (*Section, error) {
	if len(section) == 0 {
		err := &emptySecError{
			fun : "NewSection",
		}
		return nil, err
	}

	c.sectionList = append(c.sectionList, section)

	sec := &Section{
		conf : c,
		name : section,
		keys : make(map[string]*Key),
		keysHash : make(map[string]string),
	}
	c.sections[section] = sec
	return sec, nil
}

// 本函数重新打开`Configuration`绑定的文件，并重新解析该文件
func (c *Configuration)Reload() error {
	readcloser, err := os.Open(c.sourceFile)
	defer readcloser.Close()
	if err != nil {
		return &fileNotExistError{file : c.sourceFile}
	}
	return parse(c, readcloser)
}

func (c *Configuration)SourceFile() string {
	return c.sourceFile
}

// 根据`@name`返回Configuration中对应的Section指针
func (c *Configuration) GetSection(name string) (*Section, error) {
	if len(name) == 0 {
		name = DefaultSection
	}
	sec := c.sections[name]
	if sec == nil {
		return nil, &sectionNotExistError{
			conf : c.sourceFile,
			required : name,
		}
	}
	return sec, nil
}

// 根据`@name`返回Configuration中对应的Section指针。
// 若该Section不存在，则新建一个绑定至Configuration的Section
func (c *Configuration) Section(name string) *Section {
	sec, err := c.GetSection(name)
	if err != nil {
		// Note: It's OK here because the only possible error is empty section name,
		// but if it's empty, this piece of code won't be executed.
		sec, _ = c.NewSection(name)
	}
	return sec
}

// 返回当前Configuration实例中的Section列表
func (c *Configuration) Sections() []*Section {
	sections := make([]*Section, len(c.sectionList))
	for i, name := range c.sectionList {
		sections[i] = c.sections[name]
	}
	return sections
}

// 返回由当前Configuration实例的内容构造的字符串，便于打印及调试
func (c *Configuration) String() string {
	var builder strings.Builder
	builder.WriteString(fmt.Sprintf("source file: %v\n", c.SourceFile()))
	for _, sec  := range c.Sections(){
		builder.WriteString(fmt.Sprintf("[%v]", sec.Name()))
		builder.WriteString(fmt.Sprintf("%v\n", sec.Comment()))
		for _, key := range sec.Keys(){
			builder.WriteString(fmt.Sprintf("%v\n", key.Comment()))
			builder.WriteString(fmt.Sprintf("%v = ", key.Name()))
			builder.WriteString(fmt.Sprintf("%v\n\n", key.Value()))
		}
	}
	return builder.String()
}